package com.datoucai.controller;

import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.datoucai.dto.ExportSensitiveWordDto;
import com.datoucai.entity.TbSensitiveWordsExample;
import com.datoucai.param.AddSensitiveWordParam;
import com.datoucai.param.BaseResult;
import com.datoucai.service.ISensitiveService;
import com.datoucai.service.dto.SensitiveWordDto;
import com.datoucai.utils.BaseResultUtils;
import com.datoucai.utils.DateUtils;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * 敏感词controller
 */
@RestController
@RequestMapping("/sensitivewords")
@Slf4j
@RefreshScope
public class SensitiveWordController {

    /**
     * 导出数量上线
     */
    @Value("${sensitive.export.num.limit:1000}")
    private Integer exportNumLimit;
    private static final int EXPORT_NUM_LIMIT = 1000;
    /**
     * excel文件后缀
     */
    private static final String EXCEL_FILE_SUFFIX = ".xlsx";
    @Autowired
    private ISensitiveService sensitiveService;

    @RequestMapping(value = "/add",method = RequestMethod.POST)
    public BaseResult<Boolean> addWord(@RequestBody AddSensitiveWordParam param){
        try {
            log.info("增加敏感词-controller层-addWord-入参:{}", JSON.toJSONString(param));
            SensitiveWordDto sensitiveWordDto = new SensitiveWordDto();
            sensitiveWordDto.setWord(param.getWord());
            sensitiveWordDto.setCategory(param.getCategory());
            int insert = sensitiveService.insert(sensitiveWordDto);
            log.info("增加敏感词-controller层-addWord-出参:{}", insert);
            return BaseResultUtils.generateSuccess(insert>0);
        }catch (Exception e){
            log.error("增加敏感词-controller层-addWord-异常:", e);
            return BaseResultUtils.generateFail("增加敏感词异常:"+e.getMessage());
        }
    }

    /**
     * 批量导入
     * @param file
     * @return
     */
    @RequestMapping(value = "/import",method = RequestMethod.POST)
    public BaseResult<Integer> importWords(MultipartFile file){
        try {

            InputStream inputStream = file.getInputStream();
            ExcelReader reader = ExcelUtil.getReader(inputStream);

            List<List<Object>> list = reader.read(1);
            int total = 0;
            for (int i = 0; i < list.size(); i++) {
                List<Object> objects = list.get(i);
                if(objects.isEmpty() || objects.get(0) == null || objects.get(1)==null){
                    log.warn("这里有空数据:{}",objects.isEmpty()?null:JSON.toJSONString(objects));
                    continue;
                }
                SensitiveWordDto sensitiveWordDto = new SensitiveWordDto();
                sensitiveWordDto.setWord(objects.get(0).toString());
                sensitiveWordDto.setCategory(objects.get(1).toString());

                int insert = sensitiveService.insert(sensitiveWordDto);
                total += insert;
            }
            log.info("批量导入敏感词-controller层-importWords-插入敏感词数量:{}", total);

            return BaseResultUtils.generateSuccess(total);
        }catch (Exception e){
            log.error("批量导入敏感词-controller层-importWords-异常:", e);
            return BaseResultUtils.generateFail("importWords-异常:"+e.getMessage());
        }
    }
    /**
     * 导出敏感词
     * @param response
     * @return
     *
     */
    @RequestMapping(value = "/export",method = RequestMethod.GET)
    public BaseResult<Boolean> exportWords(HttpServletResponse response){
        try {
            TbSensitiveWordsExample tbSensitiveWordsExample = new TbSensitiveWordsExample();
            tbSensitiveWordsExample.setLimit(1000);
            List<SensitiveWordDto> dataList = sensitiveService.queryByParam(tbSensitiveWordsExample);

            // 通过工具类创建writer，默认创建xls格式
            ExcelWriter writer = ExcelUtil.getWriter();
            // 一次性写出内容，使用默认样式，强制输出标题
            writer.write(dataList, true);
            log.info("输出一行日志");
            //response为HttpServletResponse对象
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            //test.xls是弹出下载对话框的文件名，不能为中文，中文请自行编码
            response.setHeader("Content-Disposition","attachment;filename=test.xls");
            //out为OutputStream，需要写出到的目标流
            ServletOutputStream out= null;
            try {
                out = response.getOutputStream();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            writer.flush(out, true);
            // 关闭writer，释放内存
            writer.close();
            //此处记得关闭输出Servlet流
            IoUtil.close(out);
            return BaseResultUtils.generateSuccess(true);
        }catch (Exception e){
            log.error("批量导出敏感词-controller层-exportWords-异常:", e);
            return BaseResultUtils.generateFail("exportWords-异常:"+e.getMessage());
        }
    }

    /**
     * 导出敏感词-新
     * 问题1：导出全部
     * 问题2：参数没校验
     * 问题3：资源管理
     * 问题4：用户体验问题，异常的时候，给用户提示
     * 问题5：性能问题
     * 问题6：文件名字无区分性
     * @param response
     * @return
     */
    @RequestMapping(value = "/exportNew",method = RequestMethod.GET)
    public void exportNewWords(@RequestParam(value = "category",required = false)String category,HttpServletResponse response){
        try {
            //在处理Servlet输出流时，‌通常情况下，‌不需要手动关闭ServletOutputStream。‌这是因为当响应处理完成时，‌Servlet容器（‌如Tomcat）‌会自动关闭与响应关联的输出流。‌如果你尝试手动关闭这个流，‌可能会导致一些不可预见的问题
//        try (ServletOutputStream outputStream = response.getOutputStream()){
            // 构建查询条件
            TbSensitiveWordsExample tbSensitiveWordsExample = buildTbSensitiveWordsQueryCondition(category);
            log.info("导出查询条件:{}",exportNumLimit);

            List<SensitiveWordDto> dataList = sensitiveService.queryByParam(tbSensitiveWordsExample);
            // 数据转换，转换为导出DTO
            List<ExportSensitiveWordDto> exportSensitiveWordDtoList =  buildExportSensitiveWords(dataList);

            // 为了使浏览器能够正确识别并下载文件，设置了响应的内容类型为Excel（"application/vnd.ms-excel"），并指定了字符编码为UTF-8
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());

            String fileName = URLEncoder.encode("导出敏感词-"+DateUtils.getCurrentTimeStr()+EXCEL_FILE_SUFFIX, StandardCharsets.UTF_8.name());
            // 通过Content-Disposition头部告诉浏览器这是一个需要下载的文件，并使用URL编码确保文件名在各种浏览器中都能正确显示
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);

            EasyExcel.write(response.getOutputStream(),ExportSensitiveWordDto.class).sheet("大头菜敏感词").doWrite(exportSensitiveWordDtoList);
        }catch (Exception e){
            log.error("批量导出敏感词-controller层-exportWords-异常:", e);
        }
    }

    private static TbSensitiveWordsExample buildTbSensitiveWordsQueryCondition(String category) {
        TbSensitiveWordsExample tbSensitiveWordsExample = new TbSensitiveWordsExample();
        TbSensitiveWordsExample.Criteria criteria = tbSensitiveWordsExample.createCriteria();
        if(StringUtils.isNotBlank(category)){
            criteria.andCategoryEqualTo(category);
        }
        tbSensitiveWordsExample.setLimit(EXPORT_NUM_LIMIT);
        return tbSensitiveWordsExample;
    }

    private List<ExportSensitiveWordDto> buildExportSensitiveWords(List<SensitiveWordDto> dataList) {
        if(CollectionUtils.isEmpty(dataList)){
            return new ArrayList<>();
        }
        List<ExportSensitiveWordDto> targetList = new ArrayList<>();

        for (int i = 0; i < dataList.size(); i++) {
            SensitiveWordDto source = dataList.get(i);
            if(source==null){
                continue;
            }
            ExportSensitiveWordDto target = new ExportSensitiveWordDto();
            BeanUtils.copyProperties(source,target);
            targetList.add(target);
        }
        return targetList;
    }
}
